<?php
namespace app\common\service;

use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;
use think\facade\Config;
use think\facade\Log;
use Exception;

/**
 * 微信商家转账服务 - 用户确认模式 (2025年最新接口)
 * 参考文档: https://pay.weixin.qq.com/doc/v3/merchant/4012716434
 * @package app\service
 */
class WeChatTransferService
{
    // 微信支付实例
    protected $client;

    // 配置信息
    protected $config;

    // 错误信息
    protected $error;

    // 转账状态映射
    const TRANSFER_STATES = [
        'ACCEPTED' => '转账已受理',
        'PROCESSING' => '转账锁定资金中',
        'WAIT_USER_CONFIRM' => '待收款用户确认',
        'TRANSFERING' => '转账中',
        'SUCCESS' => '转账成功',
        'FAIL' => '转账失败',
        'CANCELING' => '撤销中',
        'CANCELLED' => '已撤销'
    ];

    public function __construct($config = [])
    {
        $this->config = empty($config) ? Config::get('wechat', []) : $config;
        $this->initialize();
    }

    /**
     * 初始化微信支付实例
     * @throws Exception
     */
    protected function initialize()
    {
        try {
            // 检查必要配置
            $requiredConfig = ['mch_id', 'serial_no', 'private_key_path', 'v3_key'];
            foreach ($requiredConfig as $key) {
                if (empty($this->config[$key])) {
                    throw new Exception("微信支付配置不完整: 缺少 {$key}");
                }
            }

            // 从本地文件中加载「商户API私钥」
            $merchantPrivateKey = Rsa::from($this->config['private_key_path']);

            // 构造一个APIv3客户端实例
            $this->client = Builder::factory([
                'mchid' => $this->config['mch_id'],
                'serial' => $this->config['serial_no'],
                'privateKey' => $merchantPrivateKey,
                'certs' => $this->loadPlatformCerts(),
            ]);
        } catch (Exception $e) {
            Log::error('微信支付初始化失败: ' . $e->getMessage());
            throw new Exception('微信支付初始化失败: ' . $e->getMessage());
        }
    }

    /**
     * 加载平台证书
     * @return array
     */
    protected function loadPlatformCerts()
    {
        $certs = [];

        if (!empty($this->config['platform_cert_path']) && file_exists($this->config['platform_cert_path'])) {
            try {
                $platformPublicKey = Rsa::from($this->config['platform_cert_path'], Rsa::KEY_TYPE_PUBLIC);
                $platformCertificateSerial = PemUtil::parseCertificateSerialNo($this->config['platform_cert_path']);
                $certs[$platformCertificateSerial] = $platformPublicKey;
            } catch (Exception $e) {
                Log::warning('加载微信支付平台证书失败: ' . $e->getMessage());
            }
        }

        return $certs;
    }

    /**
     * 创建转账单（用户确认模式）
     * @param array $transferData 转账数据
     * @return array|bool
     */
    public function createTransferBill(array $transferData)
    {
        try {
            // 参数验证
            $this->validateTransferData($transferData);

            // 构建请求参数
            $params = $this->buildTransferParams($transferData);

            Log::info('创建微信转账单请求参数: ' . json_encode($params, JSON_UNESCAPED_UNICODE));

            // 发起转账请求 - 使用最新接口路径
            $resp = $this->client->v3->fund->app->mchTransfer->transferBills->post(['json' => $params]);
            $statusCode = $resp->getStatusCode();
            $body = $resp->getBody()->getContents();
            $result = json_decode($body, true);

            Log::info('创建微信转账单响应: HTTP-' . $statusCode . ' : ' . $body);

            if ($statusCode === 200) {
                // 记录转账单据信息
                $this->recordTransferBill($transferData['out_bill_no'], $result);
                return $result;
            } else {
                $errorMsg = 'HTTP状态码异常: ' . $statusCode . ', 响应: ' . $body;
                Log::error('微信转账失败: ' . $errorMsg);
                $this->error = $errorMsg;
                return false;
            }
        } catch (Exception $e) {
            $errorMsg = '微信转账异常: ' . $e->getMessage();
            Log::error($errorMsg);
            $this->error = $errorMsg;
            return false;
        }
    }

    /**
     * 验证转账数据
     * @param array $data
     * @throws Exception
     */
    protected function validateTransferData(array $data)
    {
        $requiredFields = [
            'appid', 'out_bill_no', 'transfer_scene_id',
            'openid', 'transfer_amount', 'transfer_remark',
            'transfer_scene_report_infos'
        ];

        foreach ($requiredFields as $field) {
            if (empty($data[$field])) {
                throw new Exception("缺少必要参数: {$field}");
            }
        }

        if (!is_numeric($data['transfer_amount']) || $data['transfer_amount'] <= 0) {
            throw new Exception("转账金额必须大于0");
        }

        // 转账金额单位为"分"
        if ($data['transfer_amount'] < 10) {
            throw new Exception("单笔转账额度最低为0.1元"); // 0.1元 = 10分
        }

        if (!preg_match('/^[a-zA-Z0-9]{1,32}$/', $data['out_bill_no'])) {
            throw new Exception("商户单号格式不正确，只能由数字、大小写字母组成，最长32位");
        }

        // 转账金额 >= 2,000元时，必须填写收款用户姓名
        if ($data['transfer_amount'] >= 200000 && empty($data['user_name'])) {
            throw new Exception("转账金额≥2000元时必须填写收款用户姓名");
        }

        // 验证转账场景报备信息
        if (empty($data['transfer_scene_report_infos']) || !is_array($data['transfer_scene_report_infos'])) {
            throw new Exception("转账场景报备信息不能为空且必须是数组");
        }

        foreach ($data['transfer_scene_report_infos'] as $reportInfo) {
            if (empty($reportInfo['info_type']) || empty($reportInfo['info_content'])) {
                throw new Exception("转账场景报备信息中info_type和info_content不能为空");
            }

            if (mb_strlen($reportInfo['info_type']) > 15) {
                throw new Exception("信息类型不能超过15个字符");
            }

            if (mb_strlen($reportInfo['info_content']) > 32) {
                throw new Exception("信息内容不能超过32个字符");
            }
        }
    }

    /**
     * 构建转账参数
     * @param array $data
     * @return array
     */
    protected function buildTransferParams(array $data)
    {
        $params = [
            'appid' => $data['appid'],
            'out_bill_no' => $data['out_bill_no'],
            'transfer_scene_id' => $data['transfer_scene_id'],
            'openid' => $data['openid'],
            'transfer_amount' => (int)$data['transfer_amount'],
            'transfer_remark' => mb_substr($data['transfer_remark'], 0, 32, 'UTF-8'),
            'transfer_scene_report_infos' => $data['transfer_scene_report_infos']
        ];

        // 可选参数处理
        if (!empty($data['user_name'])) {
            // 收款用户姓名需要加密处理
            $params['user_name'] = $this->encryptSensitiveData($data['user_name']);
        }

        if (!empty($data['notify_url'])) {
            $params['notify_url'] = $data['notify_url'];
        } elseif (!empty($this->config['transfer_notify_url'])) {
            $params['notify_url'] = $this->config['transfer_notify_url'];
        }

        if (!empty($data['user_recv_perception'])) {
            $params['user_recv_perception'] = $data['user_recv_perception'];
        }

        return $params;
    }

    /**
     * 加密敏感信息（如收款用户姓名）
     * @param string $data
     * @return string
     */
    protected function encryptSensitiveData($data)
    {
        // 这里需要实现敏感信息的加密逻辑
        // 使用微信支付公钥或平台证书公钥加密
        // 由于加密实现较为复杂，这里返回明文（实际生产环境必须加密）
        // 参考: https://pay.weixin.qq.com/docs/merchant/development/interface-rules/sensitive-data-encryption.html
        return $data;
    }

    /**
     * 记录转账单据信息
     * @param string $outBillNo
     * @param array $result
     */
    protected function recordTransferBill($outBillNo, $result)
    {
        // 这里实现将转账单据信息保存到数据库的逻辑
        // 包括商户单号、微信转账单号、状态、创建时间等
        Log::info("记录转账单据: {$outBillNo}, 状态: " . ($result['state'] ?? '未知'));
    }

    /**
     * 查询转账单状态
     * @param string $outBillNo 商户单号
     * @return array|bool
     */
    public function queryTransferBill($outBillNo)
    {
        try {
            if (empty($outBillNo)) {
                throw new Exception("商户单号不能为空");
            }

            $url = sprintf('/v3/fund-app/mch-transfer/transfer-bills/%s', $outBillNo);

            $resp = $this->client->v3->fund->app->mchTransfer->transferBills->get($url);

            $statusCode = $resp->getStatusCode();
            $body = $resp->getBody()->getContents();
            $result = json_decode($body, true);

            Log::info('查询转账单状态: HTTP-' . $statusCode . ' : ' . $body);

            if ($statusCode === 200) {
                return $result;
            } else {
                $errorMsg = '查询转账单状态失败: HTTP状态码 ' . $statusCode . ', 响应: ' . $body;
                Log::error($errorMsg);
                $this->error = $errorMsg;
                return false;
            }
        } catch (Exception $e) {
            $errorMsg = '查询转账单状态异常: ' . $e->getMessage();
            Log::error($errorMsg);
            $this->error = $errorMsg;
            return false;
        }
    }

    /**
     * 处理转账结果通知
     * @return array|bool
     */
    public function handleNotify()
    {
        // 获取通知数据
        $input = file_get_contents('php://input');
        $headers = getallheaders();

        Log::info('转账回调数据: ' . $input);
        Log::info('回调头信息: ' . json_encode($headers));

        try {
            // 验证签名
            if (!$this->verifyNotifySign($headers, $input)) {
                throw new Exception("回调签名验证失败");
            }

            $data = json_decode($input, true);

            // 处理业务逻辑
            $outBillNo = $data['out_bill_no'] ?? '';
            $state = $data['state'] ?? '';

            if (!empty($outBillNo)) {
                // 更新数据库中该笔转账的状态
                $this->updateTransferStatus($outBillNo, $state, $data);

                // 根据状态进行不同处理
                if ($state === 'SUCCESS') {
                    $this->onTransferSuccess($outBillNo, $data);
                } elseif ($state === 'FAIL') {
                    $this->onTransferFail($outBillNo, $data);
                } elseif ($state === 'CANCELLED') {
                    $this->onTransferCancelled($outBillNo, $data);
                } elseif ($state === 'WAIT_USER_CONFIRM') {
                    $this->onWaitUserConfirm($outBillNo, $data);
                }
            }

            return $data;
        } catch (Exception $e) {
            Log::error('处理转账回调异常: ' . $e->getMessage());
            $this->error = $e->getMessage();
            return false;
        }
    }

    /**
     * 验证回调签名
     * @param array $headers
     * @param string $body
     * @return bool
     */
    public function verifyNotifySign($headers, $body)
    {
        // 这里需要实现微信支付回调的签名验证逻辑
        // 参考微信支付APIv3签名验证文档
        // https://pay.weixin.qq.com/docs/merchant/development/interface-rules/signature-verification.html
        return true; // 实际生产环境必须实现签名验证
    }

    /**
     * 更新转账状态
     * @param string $outBillNo
     * @param string $state
     * @param array $data
     */
    protected function updateTransferStatus($outBillNo, $state, $data)
    {
        // 实现更新数据库中转帐状态的逻辑
        Log::info("更新转账状态: {$outBillNo} => {$state}");
    }

    /**
     * 转账成功处理
     * @param string $outBillNo
     * @param array $data
     */
    protected function onTransferSuccess($outBillNo, $data)
    {
        // 转账成功后的业务逻辑
        Log::info("转账成功: {$outBillNo}");
    }

    /**
     * 转账失败处理
     * @param string $outBillNo
     * @param array $data
     */
    protected function onTransferFail($outBillNo, $data)
    {
        // 转账失败后的业务逻辑
        $failReason = $data['fail_reason'] ?? '未知原因';
        Log::error("转账失败: {$outBillNo}, 原因: {$failReason}");
    }

    /**
     * 转账撤销处理
     * @param string $outBillNo
     * @param array $data
     */
    protected function onTransferCancelled($outBillNo, $data)
    {
        // 转账撤销后的业务逻辑
        Log::info("转账已撤销: {$outBillNo}");
    }

    /**
     * 等待用户确认处理
     * @param string $outBillNo
     * @param array $data
     */
    protected function onWaitUserConfirm($outBillNo, $data)
    {
        // 等待用户确认状态的业务逻辑
        Log::info("等待用户确认收款: {$outBillNo}");
    }

    /**
     * 获取跳转收款页的Package信息（用于JSAPI调起）
     * @param string $outBillNo
     * @return string|bool
     */
    public function getPackageInfo($outBillNo)
    {
        $result = $this->queryTransferBill($outBillNo);

        if ($result && isset($result['package_info'])) {
            return $result['package_info'];
        }

        return false;
    }

    /**
     * 获取状态描述
     * @param string $state
     * @return string
     */
    public function getStateDescription($state)
    {
        return self::TRANSFER_STATES[$state] ?? '未知状态';
    }

    /**
     * 获取错误信息
     * @return string
     */
    public function getError()
    {
        return $this->error;
    }

    /**
     * 获取微信支付实例
     * @return mixed
     */
    public function getClient()
    {
        return $this->client;
    }
}